package com.songcha.library_network.api


import com.google.gson.Gson
import com.google.gson.GsonBuilder
import com.songcha.library_network.api.adapter.DoubleTypeAdapter
import com.songcha.library_network.api.adapter.FloatTypeAdapter
import com.songcha.library_network.api.adapter.IntTypeAdapter
import com.songcha.library_network.api.adapter.LongTypeAdapter
import com.songcha.library_network.api.factory.BaseConverterFactory
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import org.apache.http.conn.ssl.AllowAllHostnameVerifier
import retrofit2.Retrofit
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory
import java.security.cert.CertificateException
import java.security.cert.X509Certificate
import java.util.concurrent.TimeUnit
import javax.net.ssl.HostnameVerifier
import javax.net.ssl.SSLContext
import javax.net.ssl.SSLSession
import javax.net.ssl.TrustManager
import javax.net.ssl.X509TrustManager


object RetrofitClient {

    const val CONNECT_TIMEOUT=30L
    const val READ_TIMEOUT=30L
    const val WRITE_TIMEOUT=30L

    @JvmStatic
    fun <T> createApi(baseUrl:String,cls:Class<T>,block:(OkHttpClient.Builder)->Unit):T{
        return createApiByTimeout(baseUrl,cls,CONNECT_TIMEOUT,READ_TIMEOUT,WRITE_TIMEOUT,block)
    }

    @JvmStatic
    fun <T> createApiByTimeout(baseUrl:String,cls:Class<T>,connectTimout:Long,readTimout:Long,writeTimout:Long, block:(OkHttpClient.Builder)->Unit):T{
        val client=OkHttpClient.Builder()
            .apply {
                connectTimeout(connectTimout,TimeUnit.SECONDS)
                readTimeout(readTimout,TimeUnit.SECONDS)
                writeTimeout(writeTimout,TimeUnit.SECONDS)
                //retryOnConnectionFailure(true)
                addInterceptor(HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY))
                /*hostnameVerifier(object :HostnameVerifier{
                    //trust all certificate
                    override fun verify(hostname: String?, session: SSLSession?): Boolean {
                        return true
                    }
                })*/
                hostnameVerifier(AllowAllHostnameVerifier())

                block(this)

                //addInterceptor(MyInterceptor())
            }.build()

        /*

        val trustAllCerts = arrayOf<TrustManager>(object : X509TrustManager {
            @Throws(CertificateException::class)
            override fun checkClientTrusted(
                x509Certificates: Array<X509Certificate>,
                s: String
            ) {
            }

            @Throws(CertificateException::class)
            override fun checkServerTrusted(
                x509Certificates: Array<X509Certificate>,
                s: String
            ) {
            }

            override fun getAcceptedIssuers(): Array<X509Certificate> {
                return arrayOf()
            }
        })

        try {
            val sslContext = SSLContext.getInstance("TLS")
            sslContext.init(null, trustAllCerts,  java.security.SecureRandom())

            client.sslSocketFactory = sslContext.getSocketFactory()

        } catch (e:Exception) {
            e.printStackTrace()
        }*/


        val retrofit=Retrofit.Builder().apply {
            baseUrl(baseUrl)
            client(client)
            //json convert factory
            addConverterFactory(BaseConverterFactory.create(buildGson()))
            //point return what type on api
            addCallAdapterFactory(RxJava2CallAdapterFactory.create())
            //addCallAdapterFactory(CoroutineCallAdapterFactory())
        }.build()

        return retrofit.create(cls)
    }

    //handle null or empty str
    //if not include int filed,this field is 0
    //if not include string field,this field is null
    private fun buildGson(): Gson{
        val gson=GsonBuilder()
            .registerTypeAdapter(Int::class.java,IntTypeAdapter())
            .registerTypeAdapter(Long::class.java, LongTypeAdapter())
            .registerTypeAdapter(Float::class.java, FloatTypeAdapter())
            .registerTypeAdapter(Double::class.java, DoubleTypeAdapter())
            .create()
        return gson
    }


}